<?php


namespace App\Http\Library;


class Cache
{

    /*缓存连接*/
    private static $conn;
    /*缓存建立连接的时间*/
    private static $connTime = 0;


    /**
     * 事务
     *
     * @param \Closure $callback
     *
     * @return bool
     */
    public static function transaction(\Closure $callback)
    {
        // 调用示例:
        /*Cache::transaction(function() use ($val) {
            Cache::zrem(KEY1, [1]);
            Cache::rpush(KEY2, [2]);
        });*/

        /*开始事务*/
        self::conn()->multi();
        /*命令入队*/
        $callback();
        /*执行事务*/
        if (self::conn()->exec() === false) {
            /*取消事务，放弃执行事务块内的所有命令*/
            self::conn()->discard();
            return false;
        }
        return true;
    }


    /**
     * 取消 WATCH 命令对所有 key 的监视，如果watch监视之后执行了exec或discard，会自动取消监视，不必再unwatch
     *
     * @param array $keys
     *
     * @return mixed
     */
    public static function unwatch(array $keys)
    {
        return self::conn()->unwatch($keys);
    }


    /**
     * 监视一个(或多个) key ，如果在事务执行之前这个(或这些) key 被其他命令所改动，那么事务将被打断
     *
     * @param array $keys
     *
     * @return mixed
     */
    public static function watch(array $keys)
    {
        return self::conn()->watch($keys);
    }


    /**
     * 移除有序集中的指定成员，不存在的成员将被忽略
     *
     * @param string $key
     * @param        $val
     *
     * @return mixed
     */
    public static function zrem(string $key, $val)
    {
        return self::conn()->zrem($key, serialize($val));
    }


    /**
     * 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)次序排列
     *
     * @param string $key
     * @param int    $min int类型分数
     * @param int    $max int类型分数
     *
     * @return array
     */
    public static function zrangebyscore(string $key, int $min, int $max)
    {
        $list = self::conn()->zrangebyscore($key, $min, $max, [
            'WITHSCORES' => true,
            /*每次取数<1000*/
            'LIMIT'      => [0, 1000]
        ]);
        if (empty($list)) {
            return [];
        }
        $data = [];
        foreach ($list as $key => $val) {
            $data[] = unserialize($key);
        }
        unset($list);
        return $data;
    }


    /**
     * 向有序集合写入一个成员
     *
     * @param string $key
     * @param int    $score int类型分数,集合中的成员进行从小到大的排序
     * @param        $val   成员,不允许重复的成员
     *
     * @return mixed
     */
    public static function zadd(string $key, int $score, $val)
    {
        return self::conn()->zadd($key, $score, serialize($val));
    }


    /**
     * 移除列表的最后一个元素,返回值为移除的元素
     *
     * @param string $key
     *
     * @return mixed
     */
    public static function rpop(string $key)
    {
        return @unserialize(self::conn()->rpop($key));
    }


    /**
     * 移出并获取列表的第一个元素,返回值为移除的元素(如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止)
     *
     * @param string $key
     *
     * @return mixed
     */
    public static function blpop(string $key, $ttl = 3)
    {
        $blpop = self::conn()->blpop($key, $ttl);
        if (!empty($blpop)) {
            return @unserialize(array_pop($blpop));
        }
    }


    /**
     * 移出并获取列表的第一个元素,返回值为移除的元素
     *
     * @param string $key
     *
     * @return mixed
     */
    public static function lpop(string $key)
    {
        return @unserialize(self::conn()->lpop($key));
    }


    /**
     * 获取存储到列表的数据
     *
     * @param string $key
     * @param int    $offset 起始游标
     * @param int    $cut    终止游标
     *
     * @return mixed
     */
    public static function lrange(string $key, int $offset = 0, int $cut = 0)
    {
        $lrange = self::conn()->lrange($key, $offset, $cut);
        if (empty($lrange)) {
            return [];
        }
        foreach ($lrange as &$v) {
            $v = @unserialize($v);
        }

        return $lrange;
    }


    /**
     * 列表尾部追加数据
     *
     * @param string $key
     * @param        $val
     *
     * @return mixed
     */
    public static function rpush(string $key, $val)
    {
        return self::conn()->rpush($key, serialize($val));
    }


    /**
     * 列表头部插入数据
     *
     * @param string $key
     * @param        $val
     *
     * @return mixed
     */
    public static function lpush(string $key, $val)
    {
        return self::conn()->lpush($key, serialize($val));
    }


    /**
     * 删除指定key
     *
     * @param string $key
     */
    public static function del(string $key)
    {
        if (empty($key) || $key == '*') {
            return null;
        }
        return self::conn()->del($key);
    }


    /**
     * 获取缓存连接
     *
     * @return mixed
     */
    private static function conn()
    {
        /*redis timeout时间一般为十秒,这里设置9秒重连*/
        if ((time() - self::$connTime) > 9) {
            self::$connTime = time();
            /*缓存连接*/
            self::$conn = \Illuminate\Support\Facades\Cache::connection();
        }

        return self::$conn;
    }

}





/**
 * Cache.php
 *
 * 说明:
 *
 * 修改历史
 * ----------------------------------------
 * 2020/9/25 17:21:00   操作:创建
 **/
